package com.martinprobst.xqpretty;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTree;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.tree.CommonTree;

public class GUI {

  /**
   * @param args
   */
  public static void main(String[] args) {
    JFrame mainWindow = new JFrame("XQuery Parser");
    mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setWindowSize(mainWindow);
    final JTextArea queryArea = new JTextArea();
    queryArea.setBorder(BorderFactory.createLoweredBevelBorder());
    JButton button = new JButton("Parse");
    JButton showTree = new JButton("Show Tree");
    final JTextArea errors = new JTextArea();
    errors.setEditable(false);
    errors.setOpaque(false);
    button.addActionListener(new ActionListener() {

      public void actionPerformed(ActionEvent e) {
        ANTLRStringStream source = new ANTLRStringStream(queryArea.getText());
        XQueryLexer lexer = new XQueryLexer(source);
        LazyTokenStream tokenStream = new LazyTokenStream(lexer);
        XQueryParser parser = new XQueryParser(tokenStream, new DecisionAwareParseTreeBuilder(
            "XQuery"));
        parser.setCharSource(source);
        try {
          parser.module();
        } catch (RecognitionException e1) {
          // should not happen?
          e1.printStackTrace();
        }
        if (parser.errors.isEmpty()) {
          errors.setText("All OK");
        } else {
          StringBuilder txt = new StringBuilder();
          for (String error : parser.errors) {
            txt.append(error);
            txt.append('\n');
          }
          errors.setText(txt.toString());
        }
      }
    });
    showTree.addActionListener(new ActionListener() {

      public void actionPerformed(ActionEvent e) {
        ANTLRStringStream source = new ANTLRStringStream(queryArea.getText());
        XQueryLexer lexer = new XQueryLexer(source);
        LazyTokenStream tokenStream = new LazyTokenStream(lexer);
        XQueryParser parser = new XQueryParser(tokenStream, new DecisionAwareParseTreeBuilder(
            "XQuery"));
        parser.setCharSource(source);
        CommonTree result = null;
        try {
          result = parser.module().tree;
        } catch (RecognitionException e1) {
          // should not happen?
          e1.printStackTrace();
        }
        if (parser.errors.isEmpty()) {
          JFrame treeWindow = new JFrame();
          treeWindow.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
          JTree tree = new JTree();
          tree.setModel(new ASTTreeModel(result));
          tree.setCellRenderer(new ASTRenderer());
          treeWindow.getContentPane().add(tree);
          setWindowSize(treeWindow);
          treeWindow.setVisible(true);
        }
      }
    });

    JButton format = new JButton("Format");
    format.addActionListener(new ActionListener() {

      public void actionPerformed(ActionEvent e) {
        try {
          String html = Formatter.format(queryArea.getText(), Formatter.Mode.HTML);
          System.out.println(html);
          errors.setText(html);
        } catch (RecognitionException e1) {
          e1.printStackTrace();
        }
      }
    });

    JPanel panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
    panel.add(queryArea);
    panel.add(button);
    panel.add(showTree);
    panel.add(format);
    panel.add(errors);
    mainWindow.getContentPane().add(panel);
    mainWindow.validate();

    mainWindow.setVisible(true);
  }

  private static void setWindowSize(JFrame window) {
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    Dimension size = new Dimension((int)(screenSize.width * 0.5), (int)(screenSize.height * 0.75));
    window.setSize(size);
    window.setLocation((int)(screenSize.width * 0.25), (int)(screenSize.height * 0.125));
  }

  static class ASTTreeModel implements TreeModel {

    private final CommonTree root;

    ASTTreeModel(CommonTree result) {
      this.root = result;
    }

    public Object getChild(Object parent, int index) {
      return ((CommonTree)parent).getChild(index);
    }

    public int getChildCount(Object parent) {
      return ((CommonTree)parent).getChildCount();
    }

    public int getIndexOfChild(Object parent, Object child) {
      return ((CommonTree)child).getChildIndex();
    }

    public Object getRoot() {
      return root;
    }

    public boolean isLeaf(Object node) {
      return ((CommonTree)node).getChildCount() == 0;
    }

    public void removeTreeModelListener(TreeModelListener l) {
      // noop
    }

    public void addTreeModelListener(TreeModelListener l) {
      // noop
    }

    public void valueForPathChanged(TreePath path, Object newValue) {
      // noop
    }

  }

  static class ASTRenderer implements TreeCellRenderer {

    public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected,
        boolean expanded, boolean leaf, int row, boolean hasFocus) {
      CommonTree ast = (CommonTree)value;
      return new JLabel(ast.token != null ? ast.token.toString() : "null");
    }

  }
}
